home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Applications
/
Developer
/
BBFig
/
Source
/
YapDocument.m
< prev
next >
Wrap
Text File
|
1992-05-13
|
12KB
|
442 lines
/*
* YapDocument.m
* Author: Ali Ozer
* Created: Aug 28, 1988
* Modified for 0.8: Sep 1988
* Modified for 0.9 and revised: Feb & Mar 1989
* Modified for 1.0 and nibified: Jun & Jul 1989
* Modified for 2.0 and zonified: Aug 1990
* Modified: Jan 92 for BBFig by Izumi Ohzawa (izumi@pinoko.berkeley.edu)
*
* YapDocument class implements the Yap documents --- for every open
* window, we have another instance of the YapDocument class. Each instance
* loads itself into a separate zone.
*
* You may freely copy, distribute and reuse the code in this example.
* NeXT disclaims any warranty of any kind, expressed or implied,
* as to its fitness for any particular use.
*/
#import "PSText.h"
#import "YapDocument.h"
#import "YapApp.h"
#import "YapOutput.h"
#import <appkit/nextstd.h>
#import <appkit/Application.h>
#import <appkit/Font.h>
#import <appkit/PrintInfo.h>
#import <appkit/SavePanel.h>
#import <appkit/ScrollView.h>
#import <appkit/Window.h>
#import <appkit/TextField.h>
#import <appkit/Panel.h>
#import <appkit/Text.h>
#import <objc/List.h>
#import <streams/streams.h>
#import <defaults.h>
#import <mach.h>
#import <string.h>
#import <zone.h>
#define XOFFSET 5.0 // Offset of subsequent windows
#define YOFFSET -20.0
#define MAXSIZE 1.0e38 // Maximum size of a text object
#define UNTITLED "UNTITLED"
@implementation YapDocument
static char strbuf[128];
/*
* The next two methods allow us to cache/reuse zones.
*/
static id zoneList = nil;
+ (NXZone *)newZone
{
if (!zoneList || ![zoneList count]) {
return NXCreateZone(vm_page_size, vm_page_size, YES);
} else {
return (NXZone *)[zoneList removeLastObject];
}
}
+ (void)reuseZone:(NXZone *)aZone
{
if (!zoneList) zoneList = [List new];
[zoneList addObject:(id)aZone];
}
/*
* Create a new instance of YapDocument with the specified file in the
* buffer. If the file cannot be opened, no document is created and nil
* is returned.
*/
+ newFromFile:(const char *)fileName
{
NXStream *stream = NULL;
id docWin; /* Window belonging to this document. */
id textObj; /* The text object we put in the window. */
NXRect textFrame; /* The frame of the text object in our window */
if (fileName && !(stream = NXMapFile(fileName, NX_READONLY))) {
return nil;
}
self = [[self allocFromZone:[self newZone]] init];
if (![NXApp loadNibSection:"Document.nib" owner:self withNames:NO fromZone:[self zone]]) {
NXCloseMemory (stream, NX_FREEBUFFER);
[self free];
return nil;
}
/*
* Loading the nib file above sets the document outlet to the
* scrollview that contains PS code;
* so we can use this outlet to get at the window & such.
*/
docWin = [document window];
[[document docView] getFrame:&textFrame];
/*
* Put the window offset from the previous document window... If no
* previous window exists, or the main window is undetermined, then
*/
if ([NXApp mainWindow]) {
NXRect winFrame, winLoc;
[[NXApp mainWindow] getFrame:&winFrame];
[[docWin class] getContentRect:&winLoc
forFrameRect:&winFrame
style:[docWin style]];
[docWin moveTo:NX_X(&winLoc) + XOFFSET :NX_Y(&winLoc) + YOFFSET];
}
[self setName:UNTITLED];
[docWin setDelegate:self];
if (stream) {
char *text;
int len, maxLen;
NXGetMemoryBuffer (stream, &text, &len, &maxLen);
textObj = [[PSText allocFromZone:[self zone]] initFrame:&textFrame text:text alignment:NX_LEFTALIGNED];
[self setName:fileName];
NXCloseMemory (stream, NX_FREEBUFFER);
} else {
textObj = [[PSText allocFromZone:[self zone]] initFrame:&textFrame];
[self setName:UNTITLED];
}
/*
* Put this new text object in the window and free the IB-created one.
*/
[[document setDocView:textObj] free];
/*
* Set various parameters.
*/
[document setAutoresizeSubviews:YES];
[textObj setVertResizable:YES]; // Grow down as you type
[textObj setHorizResizable:NO]; // Let it do sideways too
[textObj setMonoFont:YES];
[textObj setOpaque:YES];
[textObj setMinSize:&textFrame.size];
NX_WIDTH(&textFrame) = NX_HEIGHT(&textFrame) = MAXSIZE;
[textObj setMaxSize:&textFrame.size]; // Can grow
[textObj setSel:0:0]; // Set the selection
[textObj setDelegate:self];
[textObj sizeToFit];
[docWin makeKeyAndOrderFront:self];
[self initializePrintInfo];
return self;
}
+ new
{
return [self newFromFile:NULL];
}
- initializePrintInfo
{
static BOOL printInfoInitialized = NO;
if (!printInfoInitialized) {
[[NXApp printInfo] setVertCentered:NO];
[[NXApp printInfo] setHorizCentered:NO];
[[NXApp printInfo] setHorizPagination:NX_FITPAGINATION];
[[NXApp printInfo] setMarginLeft:36.0 right:36.0 top:72.0 bottom:72.0];
printInfoInitialized = YES;
}
return self;
}
/*
* Delegate method for the document Text object. We use this method
* to detect when the text in the window is modified.
*/
- text:text isEmpty:(BOOL)empty
{
if (![[document window] isDocEdited]) {
[[document window] setDocEdited:YES];
}
return NO;
}
/*
* Delegate method for the document Text object. We use this method
* to detect when the font is changed so we an write it out as the default.
*/
- textWillConvert:textObject fromFont:oldFont toFont:newFont
{
if (newFont) {
char str[80];
sprintf (str, "%f\0", [newFont pointSize]);
NXWriteDefault ([NXApp appName], "NXFontSize", str);
NXWriteDefault ([NXApp appName], "NXFont", [newFont name]);
[Text setDefaultFont:newFont];
}
return newFont;
}
// This fixes the problem of messed up text when you resize the
// document window.
- windowDidResize:sender
{
id docText;
docText = [document docView];
[docText calcLine];
[docText sizeToFit];
return self;
}
/*
* saveDocument: will write out the contents of the document
* to the specified file. The best (perhaps not the cleanest but the
* most efficient) way to dump a Text object to a file seems to be
* to open the file (with open()), then to use NXOpenFile(), and
* finally use writeText: to dump the contents out.
*/
- (int)saveDocument:(const char *)fileName
{
BOOL saveOK;
int fd; // File descriptor
int retval = 0;
NXStream *stream = NULL;
if (saveOK =
(((fd = open (fileName, O_WRONLY|O_CREAT|O_TRUNC, 0644)) != -1) &&
(stream = NXOpenFile (fd, NX_WRITEONLY))))
[[document docView] writeText:stream];
if (stream) NXClose (stream);
if (fd != -1) close (fd);
if (saveOK) {
[self setName:fileName];
[[document window] setDocEdited:NO];
} else {
if(NXRunAlertPanel(NULL, "Can't write file.", "OK", "Save As", NULL)
== NX_ALERTALTERNATE)
retval = -1;
}
return retval;
}
/*
* Set/Get the name of the document. This is the same as the title.
*/
// There was a bug in the original Yap v19, where filename changes for
// no reason whan saved without executed (happens when multiple files open.
// The bug has been fixed. The problem was that "name" and "documentName"
// are the identical pointers to the same memory for "Save". And the orig
// code was freeing "name" before documentName was copied to a new location.
- setName:(const char *)documentName
{
char *temp;
documentName = documentName ? documentName : "";
temp = NXCopyStringBufferFromZone (documentName, [self zone]);
if (name) free(name);
name = temp;
[[document window] setTitleAsFilename:name];
return self;
}
-(const char *)name
{
return name;
}
/*
* windowWillClose: gets called by windows who have this instance of
* YapDocument as delegate. The document simply marks itself and its zone
* to be free and lets the window know it can close. A more sophisticated
* program might want to put up an alert if the document was edited but not
* saved.
*/
- windowWillClose:sender action:(const char *)action
{
if([[document window] isDocEdited])
{
int dstatus = NXRunAlertPanel(action,
"Save edited document: %s ?",
"Save", "Don't Save", "Cancel", name);
if(dstatus == NX_ALERTDEFAULT) /* save */
[self save:self];
else if(dstatus == NX_ALERTOTHER) /* cancel */
return nil;
}
[sender setDelegate:nil];
[self free];
return sender; // We need to return a non-nil value --- here's one.
}
- windowWillClose:sender
{
return [self windowWillClose:sender action:"Close"];
}
/*
- textWillChange:sender
{
[[document window] setDocEdited:YES];
return sender;
}
*/
- free
{
NXZone *docZone = [self zone];
if (name) free(name);
[super free];
[YapDocument reuseZone:docZone];
return nil;
}
/*
* save: saves the current document. If the document is untitled, it
* puts up a savePanel to get the user to enter a file name. saveAs:
* saves the document under a new name by putting up a savePanel.
*/
- save:sender
{
const char *fileName = [self name];
if ((fileName == NULL) ||
(strcmp (fileName, UNTITLED) == 0) || (strcmp (fileName, "") == 0))
{ /* fileName is not valid, get a new one */
if ([[SavePanel new] runModalForDirectory:"." file:UNTITLED] == NO)
return self;
else
fileName = [[SavePanel new] filename];
}
if (fileName)
if([self saveDocument:fileName])
[self saveAs:self]; /* Couldn't save -- try another name */
return self;
}
- saveAs:sender
{
again:
if ([[SavePanel new] runModalForDirectory:"." file:[self name]])
{
if([self saveDocument:[[SavePanel new] filename]])
goto again;
}
return self;
}
- execute:sender
{
float llx, lly, urx, ury, bbm;
int utime;
[[NXApp outputView] executeCodeFrom:[document docView]
andReturnBB: &llx : &lly : &urx : &ury
usertime: &utime];
bbm = (float)[NXApp bbMargin];
if(utime >= 0)
{
llx -= bbm;
lly -= bbm;
urx += bbm;
ury += bbm;
sprintf(strbuf, "%%%%BoundingBox: %.0f %.0f %.0f %.0f", llx, lly, urx, ury);
}
else
strcpy(strbuf,"");
[bbTextField setStringValue: strbuf];
return self;
}
/*
* To get around the problem of printPSCode: going up the responder chain and
* causing print panel to come back after Cancel, we use the following glue.
*/
- print:sender
{
[[document docView] printPSCode:sender];
return self;
}
/*
* Insert %%BoundigBox comment in "bbTextField" into PSText
*/
- insertBB:sender
{
id docText;
// int selstart,selend;
docText = [document docView];
// [docText getSel: &selstart : &selend];
strncpy(strbuf, [bbTextField stringValue], 80);
strcat(strbuf, "\n");
[[document window] setDocEdited:YES];
[docText replaceSel: strbuf];
return self;
}
/*
* Insert %!PS-Adobe-2.0 EPSF-2.0 comment in "versionField" into PSText
*/
- insertVersion:sender
{
id docText;
docText = [document docView];
[docText setSel:0 :0];
strncpy(strbuf, [versionField stringValue], 40);
strcat(strbuf,"\n");
[[document window] setDocEdited:YES];
[docText replaceSel: strbuf];
return self;
}
/* Insert both of the above at the Top of the PSText */
- insertBoth:sender
{
id docText;
docText = [document docView];
[docText setSel:0 :0];
strncpy(strbuf, [versionField stringValue], 40);
strcat(strbuf,"\n");
strncat(strbuf, [bbTextField stringValue], 80);
strcat(strbuf, "\n");
[[document window] setDocEdited:YES];
[docText replaceSel: strbuf];
return self;
}
@end